/**
 * createStore(reducer, preloadedState, enhancer)
 */

function createStore(reducer, preloadedState, enhancer) {

  // 约束reducer参数类型
  if (typeof reducer !== 'function') throw new Error('reducer必须是函数');

  // 判断enhancer 是否传递 传递了是不是函数
  if (typeof enhancer !== 'undefined') {
    if (typeof enhancer !== 'function') {
      throw new Error('enhancer必须是函数')
    };
    return enhancer(createStore)(reducer, preloadedState);
  }

  // store对象中存储的状态
  const currentState = preloadedState;
  // 存放订阅者函数
  const currentListeners = [];

  // 获取状态
  function getState() {
    return currentState;
  };

  // 触发action
  function dispatch(action) {
    // 判断action是否是对象
    if (!isPlainObjec(action)) throw new Error('action必须是对象');
    if (action.type === 'undefined') throw new Error('action中必须存在type属性')
    currentState = reducer(currentState, action);

    currentListeners.forEach(listener => {
      listener()
    })
  };;

  // 订阅状态
  function subscribe(listener) {
    currentListeners.push(listener);
  }

  return {
    getState,
    dispatch,
    subscribe
  }
}

function isPlainObjec(obj) {
  // 排除基本数据类型和null
  if (typeof obj !== 'object' || obj === null) return false;
  // 区分数组和对象 原型对象对比的方式
  let proto = obj;
  while (Object.getPrototypeOf(proto) !== null) {
    proto = Object.getPrototypeOf(proto);
  };
  return Object.getPrototypeOf(obj) === proto;
}

function applyMiddleware(...middleware) {
  return function (createStore) {
    return function (reducer, preloadedState) {
      // 创建store
      const store = createStore(reducer, preloadedState);
      // 阉割版stroe对象
      const middlewareAPI = {
        getState: store.getState,
        dispatch: store.dispatch
      }
      // 调用中间件第一层函数 传递阉割版stroe对象
      const chain = middleware.map(middleware => middleware(middlewareAPI));
      const dispatch = compose(...chain)(store.dispatch);

      return {
        ...store,
        dispatch
      }
    }
  }
}

function compose() {
  const func = [...arguments];

  return function (dispatch) {
    for (let i = func.length - 1; i >= 0; i--) {
      dispatch = func[i](dispatch)
    }

    return dispatch;
  }
}

function bindActionCreators(actionCreators, dispatch) {
  const boundActionCreators = {};

  for (const key in actionCreators) {
    boundActionCreators[key] = function (...payload) {
      dispatch(actionCreators[key].apply(null, payload))
    }
  };

  return boundActionCreators;
}

function combineReducers(reducers) {
  // 检查reducer类型，它必须是函数
  const reducerKeys = Object.keys(reducers);
  for (let i = 0; i < reducerKeys.length; i++) {
    const key = reducerKeys[i];
    if (typeof reducers[key] !== 'function') throw new Error(' reducer必须是函数')
  }
  // 调用一个个小的reducer，将每一个小的reducer中返回状态存储在一个新的大对象中
  return function (state, action) {
    const nextState = {};
    for (let i = 0; i < reducerKeys.length; i++) {
      const key = reducerKeys[i],
        reducer = reducers[key],
        previousStateForKey = state[key];

      nextState[key] = reducer(previousStateForKey, action);
    };

    return newState;
  }
}